package com.zhuodewen.ai.util;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 通用线程池配置(仅做参考,请根据实际情况配置)
 *
 * @author 卓德文
 */
@Configuration
@Slf4j
public class CommonThreadPoolConfig {

    /**
     *  1)默认情况下，在创建了线程池后，线程池中的线程数为0，当有任务来之后，就会创建一个线程(核心线程)去执行任务
     *  2)当线程池中的核心线程数目达到corePoolSize后，就会把到达的任务放到缓存队列当中
     *  3)当核心线程+缓存队列满了，就继续创建线程(不超过最大线程数)，当线程数量大于等于maxPoolSize后，开始使用拒绝策略
     */

    /**
     * 核心线程数
     * <p>
     * CPU密集型：核心线程数 = CPU核数 + 1
     * IO密集型：核心线程数 = CPU核数 * 2
     * 注：IO密集型（某大厂实践经验）
     * 核心线程数 = CPU核数 / （1-阻塞系数）     例如阻塞系数 0.8,CPU核数为4,则核心线程数为20
     */
    private static final int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;


    /**
     * 最大线程数
     */
    private static final int maxPoolSize = ((corePoolSize + 1) * 2 + 1) * 2;


    /**
     * 允许线程空闲时间（单位：默认为秒）
     */
    private static final int keepAliveTime = 1;

    /**
     * 缓冲队列大小
     */
    private static final int queueCapacity = 200;

    /**
     * 线程池名前缀
     */
    private static final String threadNamePrefix = "Thread-Task-Common";

    /**
     * 获取通用线程池实例-单例模式
     *
     * @return ThreadPoolExecutor
     */
    public static ThreadPoolExecutor getInstance() {
        ThreadPoolExecutor instance = ThreadPoolHolder.instance;
        log.info("通用线程池实例:{}" + instance.toString());
        return instance;
    }

    /**
     * 内部类-用于初始化线程池对象
     */
    private static class ThreadPoolHolder {

        /**
         * 自定义线程池
         */
        private static ThreadPoolExecutor instance = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(queueCapacity),
                new ThreadFactoryBuilder().setNamePrefix(threadNamePrefix).build(),
                // 拒绝策略 实现RejectedExecutionHandler(不处理默认是抛出异常)
                new ThreadPoolExecutor.AbortPolicy() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                        log.error("======{}线程任务{}执行DiscardPolicy拒绝策略,isShutdown={},isTerminating={},isTerminated={},",
                                e.toString(), r.toString(), e.isShutdown(), e.isTerminating(), e.isTerminated());
                        if (!e.isShutdown()) {
                            if (r instanceof FutureTask) {
                                ((FutureTask) r).cancel(true);
                            } else {
                                r.run();
                            }
                        } else {
                            r.run();
                        }
                    }
                }
        );
    }

}